package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v7"
	"io"
	"math/rand"
	"os"
	"sync"
	"time"
)

var once sync.Once
var sha1LuaScript string
var Redis *redis.Client
var key = "goods:1"

func main() {
	Redis = redis.NewClient(&redis.Options{
		Addr:     "bjdxt.qcgameweb02.qiyi.redis:6521",
		Password: "uWu630F4DGfj",
		DB:       0,
	})

	pong, err := Redis.Ping().Result()
	fmt.Println(pong, err)

	fields := make(map[string]interface{})
	fields["id"] = 1
	fields["stock"] = 1000000
	err = Redis.HMSet(key, fields).Err()
	if err != nil {
		panic(err)
	}

	rand.Seed(time.Now().UnixNano())

	gin.SetMode(gin.ReleaseMode)
	f, _ := os.Create("gin.log")
	gin.DefaultWriter = io.MultiWriter(f)

	r := gin.Default()
	r.GET("/get1", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"map": hGet(),
		})
	})
	r.GET("/get2", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"map1": hGet(),
			"map2": hGet(),
		})
	})

	r.GET("/setnx", func(c *gin.Context) {
		key = fmt.Sprintf("key:%d", rand.Intn(1000000000))
		Redis.SetNX(key, 1, 0)
		c.JSON(200, gin.H{
			"setnx": 1,
		})
	})

	r.GET("/decrRedis", func(c *gin.Context) {
		stock := decrRedis()
		c.JSON(200, gin.H{
			"stock": stock,
		})
	})

	r.GET("/decrLuaRedis", func(c *gin.Context) {
		decrLuaRedis()
		c.JSON(200, gin.H{
			"decrLuaRedis": 0,
		})
	})

	r.Run()
}

func hGet() map[string]string {
	result, err := Redis.HGetAll(key).Result()
	if err == redis.Nil {
		fmt.Println("key2 does not exist")
	} else if err != nil {
		panic(err)
	}

	return result
}


func decrRedis() int {
	stock, err := Redis.HIncrBy(key, "stock", -1).Result()
	if err != nil {
		panic(err)
	}

	if stock < 0 {
		Redis.HIncrBy(key, "stock", 1)
	}

	return int(stock)

}

func decrLuaRedis() {
	luaScript := `
		local goodsId = KEYS[1]
		local number = KEYS[2]
	
		local key = 'goods:' .. goodsId
		local stock = redis.call('HGET', key, 'stock')
	
		if not stock or tonumber(stock) <= 0 then
		  return -1
		end
	
		redis.call('HINCRBY', key, 'stock', -number)
		return 1
	`

	once.Do(func() {
		var err error
		sha1LuaScript ,err = Redis.ScriptLoad(luaScript).Result()
		if err != nil {
			panic(err)
		}
	})

	n , err := Redis.EvalSha(sha1LuaScript , []string{"1", "1"}).Result()
	if err != nil {
		fmt.Println(n , err)
		panic(err)
	}
}
